using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Security.Permissions;
using System.Runtime.ConstrainedExecution;
using System.Security;
using System.Collections.ObjectModel;
using Microsoft.Win32.SafeHandles;

namespace qPrintComponent
{
    [Browsable(false)]
    public abstract class qSafeInfo : SafeHandleZeroOrMinusOneIsInvalid
    {
        protected int IntPtrSize = Marshal.SizeOf(typeof(IntPtr));
        internal int Level;
        
        protected SafeHandle PrinterSafeHandle;
        protected int BytesNeeded;
        protected int Size;
        
        protected abstract void RefreshInfo();
        protected abstract bool Update();

        protected qSafeInfo(SafeHandle pSafeHandle, int infoLevel) 
            : base (true)
        {
            PrinterSafeHandle = pSafeHandle;
            Level = infoLevel;
            RefreshInfo();
        }

        protected qSafeInfo(IntPtr pMemoryHandle, int infoLevel)
            : base(false)
        {
            base.handle = pMemoryHandle;
            Level = infoLevel;
        }
        
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [return: MarshalAs(UnmanagedType.U1)]
        protected override bool ReleaseHandle()
        {
            if (!IsInvalid)
            {
                if (Size > 0)
                {
                    Marshal.FreeHGlobal(base.handle);
                    base.SetHandle(IntPtr.Zero);
                }
                else
                    return true;
            }
            return true;
        }


        [SuppressUnmanagedCodeSecurity]
        protected void AllocMem()
        {
            if (Size >= BytesNeeded)
                return;
            if (Size != 0)
                Marshal.FreeHGlobal(base.handle);
            if (BytesNeeded != 0)
                base.handle = Marshal.AllocHGlobal(BytesNeeded);
            Size = BytesNeeded;
        }

        protected IntPtr PrinterHandle
        { get { return PrinterSafeHandle.DangerousGetHandle(); } }
        
        [SuppressUnmanagedCodeSecurity]
        protected short GetShortField(int offset)
        {
            if (this.IsInvalid) return 0;
            return Marshal.ReadInt16(this.handle, offset);
        }
        [SuppressUnmanagedCodeSecurity]
        internal int GetIntField(int offset)
        {
            if (this.IsInvalid) return 0;
            return Marshal.ReadInt32(this.handle, IntPtrSize * offset); 
        }
        [SuppressUnmanagedCodeSecurity]
        protected internal bool SetIntField(int offset, int val)
        {
            if (this.IsInvalid) throw new InvalidOperationException();
            Marshal.WriteInt32(this.handle, IntPtrSize * offset, val);
            return Update();
        }

        [SuppressUnmanagedCodeSecurity]
        protected long GetLongField(int offset)
        {
            if (this.IsInvalid) return 0;
            return Marshal.ReadInt64(this.handle, IntPtrSize * offset);
        }
        
        [SuppressUnmanagedCodeSecurity]
        protected internal string GetStringField(int offset)
        {
            if (this.IsInvalid) return null;
            string s = string.Empty;
            lock (this)
            {
                IntPtr ptr = Marshal.ReadIntPtr(this.handle, IntPtrSize * offset);
                s = Marshal.PtrToStringUni(ptr);
                if (s == null) s = string.Empty;
            }
            return s;
        }
        [SuppressUnmanagedCodeSecurity]
        protected bool SetStringField(int offset, string val)
        {
            if (this.IsInvalid) throw new InvalidOperationException();
            IntPtr ptr1 = Marshal.StringToHGlobalUni(val);
            Marshal.WriteIntPtr(this.handle, IntPtrSize * offset, ptr1);
            bool b = Update();
            Marshal.FreeHGlobal(ptr1);
            return b;
        }

        [SuppressUnmanagedCodeSecurity]
        protected internal IntPtr GetIntPtrField(int offset)
        {
            if (this.IsInvalid) return IntPtr.Zero;
            return Marshal.ReadIntPtr(this.handle, IntPtrSize * offset);
        }
        [SuppressUnmanagedCodeSecurity]
        protected internal bool SetIntPtrField(int offset, IntPtr val)
        {
            if (this.IsInvalid) throw new InvalidOperationException();
            Marshal.WriteIntPtr(this.handle, IntPtrSize * offset, val);
            return Update();
        }

        protected byte[] GetBytes()
        {
            if (this.IsInvalid) throw new InvalidOperationException();
            byte[] b = new byte[this.Size];
            Marshal.Copy(this.handle , b , 0 ,Size);
            return b;
        }
 
    }
}

